const path = require('path');
const fs = require('fs');
const { writeSourceToFile } = require('kolibri-format');
const logger = require('kolibri-logging');

const logging = logger.getLogger('Kolibri Intl Data');

module.exports = function (outputDir, languageInfoPath) {
  const languageInfo = require(languageInfoPath);

  // Create polyfills directory in output
  const polyfillsDir = path.resolve(outputDir, 'polyfills');
  const vueIntlPolyfillsDir = path.resolve(polyfillsDir, 'vue-intl');
  const intlPolyfillsDir = path.resolve(polyfillsDir, 'intl');

  if (!fs.existsSync(polyfillsDir)) {
    fs.mkdirSync(polyfillsDir, { recursive: true });
  }
  if (!fs.existsSync(vueIntlPolyfillsDir)) {
    fs.mkdirSync(vueIntlPolyfillsDir, { recursive: true });
  }
  if (!fs.existsSync(intlPolyfillsDir)) {
    fs.mkdirSync(intlPolyfillsDir, { recursive: true });
  }

  // Helper function to copy polyfill files
  function copyPolyfillFile(sourcePath, targetDir, filename) {
    try {
      if (fs.existsSync(sourcePath)) {
        const targetPath = path.resolve(targetDir, filename);
        fs.copyFileSync(sourcePath, targetPath);
        return true;
      }
    } catch (e) {
      logging.error(`Failed to copy polyfill file ${sourcePath}:`, e);
    }
    return false;
  }

  const commonHeader = `
  /*
  * This is an auto-generated file, any manual edits will be overridden.
  *
  * To regenerate, see instructions here:
  *   https://kolibri-dev.readthedocs.io/en/develop/i18n.html
  *
  * This file was generated by kolibri-i18n code-gen
  *
  * Polyfill files are copied to ./polyfills/ directory to avoid external dependencies.
  */
  `;
  const vueIntlHeader = `module.exports = function () {
    const data = [];`;

  function generateVueIntlItems(language) {
    /*
     * Generate entries of this form:
     *   data.push(require('vue-intl/locale-data/ar.js'));
     *
     * Some Intl codes look like 'ar' and others look like 'bn-bd', so for Vue Intl
     * we strip off the territory code if it's there.
     */
    const vue_intl_code = language.intl_code.split('-')[0];

    // Exclude ach-ug language that is defined in language_info.json
    if (vue_intl_code !== 'ach') {
      const filename = `${vue_intl_code}.js`;
      let module_path = `vue-intl/locale-data/${filename}`;

      // Try to find the source file from vue-intl package first
      try {
        require.resolve(module_path);
      } catch (e) {
        // Fall back to kolibri-i18n's bundled locale data - copy to polyfills
        try {
          const kolibriPath = require.resolve(`kolibri-i18n/src/locale-data/vue-intl/${filename}`);
          // Copy our polyfill to the output directory
          if (copyPolyfillFile(kolibriPath, vueIntlPolyfillsDir, filename)) {
            module_path = `./polyfills/vue-intl/${filename}`;
          } else {
            throw new Error(`Failed to copy kolibri-i18n vue-intl polyfill for ${vue_intl_code}`);
          }
        } catch (e) {
          logging.error(
            `${vue_intl_code} not available from vue-intl locale data and no kolibri-i18n locale data found`,
          );
          throw new Error('No vue-intl locale data');
        }
      }

      return `data.push(require('${module_path}'));`;
    }
  }

  const vueIntlFooter = `
    return data;
  };
  `;

  const vueIntlModule =
    commonHeader + vueIntlHeader + languageInfo.map(generateVueIntlItems).join('') + vueIntlFooter;

  const vueIntlModulePath = path.resolve(outputDir, 'vue-intl-locale-data.js');
  const intlHeader = `module.exports = function(locale) {
    switch (locale) {`;

  function generateIntlItems(language) {
    /*
     * Generate entries of the form:
     *
     * case 'sw-tz':
     *   return new Promise(function(resolve) {
     *     require.ensure(
     *       ['intl/locale-data/jsonp/sw-TZ.js'],
     *       function(require) {
     *         resolve(() => require('intl/locale-data/jsonp/sw-TZ.js'));
     *       }
     *     );
     *   });
     *
     * Note that not all codes have two parts, e.g. 'en' vs 'es-mx'.
     */

    // For examples, see:
    // https://github.com/andyearnshaw/Intl.js/tree/master/locale-data/jsonp
    const pattern = /^(\w{2,3})(-\w{4})?(-\w{2})?(-\d+)?$/;
    const codes = language.intl_code.match(pattern);
    if (!codes) {
      logging.error(`Unable to parse code: '${language.intl_code}'`);
    }

    let filename = '';

    // Always start with a 2- or 3-character sequence of lowercase letters
    filename += codes[1];
    if (codes[2]) {
      // Trailing four-letter strings of characters are Title-case
      filename += '-' + codes[2][1].toUpperCase() + codes[2].substring(2);
    }
    if (codes[3]) {
      // Trailing two-letter strings of characters are CAPITAL-case
      filename += codes[3].toUpperCase();
    }
    if (codes[4]) {
      // Trailing runs of numbers
      filename += codes[4];
    }

    // Exclude ach-ug language that is defined in language_info.json
    if (language.intl_code !== 'ach-ug') {
      const jsFilename = `${filename}.js`;
      let module_path = `intl/locale-data/jsonp/${jsFilename}`;

      // Try to find the source file from intl package first
      try {
        require.resolve(module_path);
      } catch (e) {
        // Fall back to kolibri-i18n's bundled locale data - copy to polyfills
        try {
          const kolibriPath = require.resolve(`kolibri-i18n/src/locale-data/intl/${jsFilename}`);
          // Copy our polyfill to the output directory
          if (copyPolyfillFile(kolibriPath, intlPolyfillsDir, jsFilename)) {
            module_path = `./polyfills/intl/${jsFilename}`;
          } else {
            throw new Error(`Failed to copy kolibri-i18n intl polyfill for ${language.intl_code}`);
          }
        } catch (e) {
          logging.error(
            `${language.intl_code} not available from intl locale data and no kolibri-i18n locale data found`,
          );
          throw new Error('No intl locale data');
        }
      }

      return `
      case '${language.intl_code}':
        return new Promise(function(resolve) {
          require.ensure(
            ['${module_path}'],
            function(require) {
              resolve(() => require('${module_path}'));
            }
          );
        });`;
    }
  }

  const intlFooter = `
      default:
        return new Promise(function(resolve) {
          require.ensure(
            ['intl/locale-data/jsonp/en.js'],
            function(require) {
              resolve(() => require('intl/locale-data/jsonp/en.js'));
            }
          );
        });
    }
  };
  `;

  const intlModule =
    commonHeader + intlHeader + languageInfo.map(generateIntlItems).join('') + intlFooter;

  const intlModulePath = path.resolve(outputDir, 'intl-locale-data.js');
  writeSourceToFile(vueIntlModulePath, vueIntlModule);

  writeSourceToFile(intlModulePath, intlModule);
};
